<template>
  <div class="dashboard-container">
    <div class="app-container">
      <el-card>
        <el-tabs>
          <!-- 放置页签 -->
          <el-tab-pane label="角色管理">
            <!-- 新增角色按钮 -->
            <el-row style="height:60px">
              <el-button
                icon="el-icon-plus"
                size="small"
                type="primary"
                @click="hAdd"
              >新增角色</el-button>
            </el-row>
            <!-- 表格 -->
            <el-table :data="roles">
              <!-- type="index": 该列为序号 1 开头 -->
              <el-table-column label="序号" width="120" type="index" />
              <el-table-column label="角色名称" width="240" prop="name" />
              <el-table-column label="描述" prop="description" />
              <el-table-column label="操作">
                <template slot-scope="scope">
                  <el-button size="small" type="success" @click="hAssign(scope.row.id)">分配权限</el-button>
                  <el-button size="small" type="primary" @click="hEdit(scope.row)">编辑</el-button>
                  <el-button size="small" type="danger" @click="hDel(scope.row.id)">删除</el-button>
                </template>
              </el-table-column>
            </el-table>

            <el-row type="flex" justify="center" align="middle" style="height: 60px">
              <!-- 分页组件 -->
              <!-- current-page: 当前页 -->
              <!-- page-size: 每页显示多少条 -->
              <!-- total: 总条数 -->
              <!-- page-sizes: 设置每页显示多少条的选项 -->
              <!-- size-change: 当 page-size 发生变化时触发 -->
              <!-- current-change: 当前页发生变化时触发 -->
              <!-- handle: 处理 -->
              <el-pagination
                :current-page="pageParams.page"
                :page-sizes="[2, 3, 5, 10]"
                :page-size="pageParams.pagesize"
                layout="total, sizes, prev, pager, next, jumper"
                :total="total"
                @size-change="hSizeChange"
                @current-change="hCurrentChange"
              />
            </el-row>
          </el-tab-pane>
        </el-tabs>
      </el-card>
    </div>
    <!-- 新增弹框 -->
    <!-- resetFields: 重置所有数据项, 还原成 "默认值", ElementUI 认为第一次赋值的内容是默认值 -->
    <el-dialog
      :title="isEdit ? '编辑' : '添加'"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
      :visible.sync="showDialog"
      @closed="hClosed"
    >
      <el-form ref="roleForm" :model="roleForm" :rules="rules" label-width="100px">
        <el-form-item label="角色名称" prop="name">
          <el-input v-model="roleForm.name" />
        </el-form-item>
        <el-form-item label="角色描述" prop="description">
          <el-input v-model="roleForm.description" />
        </el-form-item>
      </el-form>
      <!-- 底部 -->
      <el-row slot="footer" type="flex" justify="center">
        <el-col :span="6">
          <el-button size="small" @click="showDialog = false">取消</el-button>
          <el-button size="small" type="primary" @click="hSubmit">确定</el-button>
        </el-col>
      </el-row>
    </el-dialog>

    <!-- 分配权限 -->
    <el-dialog
      title="分配权限"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
      :visible.sync="showDialogAssign"
    >
      <AssignPermission v-if="showDialogAssign" :role-id="roleId" @close="showDialogAssign = false" />
    </el-dialog>
  </div>
</template>

<script>
import { addRole, delRoleById, getRoles, updateRole } from '@/api/roles'
import AssignPermission from './assignPermission.vue'

export default {
  components: {
    AssignPermission
  },
  data() {
    return {
      pageParams: {
        page: 1,
        pagesize: 2 // 参数名别写错了, 因为传错了也不报错
      },
      roles: [],
      total: 0,
      showDialog: false,
      roleForm: {
        name: '',
        description: ''
      },
      rules: {
        name: [{ required: true, message: '角色名称不能为空', trigger: 'blur' }]
      },
      isEdit: false,
      showDialogAssign: false,
      roleId: ''
    }
  },
  computed: {
    // 定义计算属性帮我们实时计算最大页码数
    // maxNum() {
    //   return Math.ceil(this.total / this.pageParams.pagesize)
    // }
  },
  created() {
    this.loadRoles()
  },
  methods: {
    async loadRoles() {
      try {
        const res = await getRoles(this.pageParams)
        // console.log(res)
        this.roles = res.data.rows
        this.total = res.data.total
      } catch (e) {
        console.log('获取角色信息失败:', e)
      }
    },
    hSizeChange(val) {
      // console.log('每页显示条数:', val)
      // 修改每页显示的条数
      this.pageParams.pagesize = val
      // 重新发起请求获取最新的数据
      this.loadRoles()
    },
    hCurrentChange(val) {
      // console.log('当前页:', val)
      // 修改当前页码值
      this.pageParams.page = val
      // 重发请求
      this.loadRoles()
    },
    async hDel(id) {
      // // 记得讲解为什么是英文!
      // // console.log(id)
      // // 1. 提醒用户是否删除
      // this.$confirm('确定删除该角色吗?', '提示', {
      //   type: 'warning'
      // })
      //   .then(async() => {
      //     try {
      //       // 2. 用户确定后, 发请求删除
      //       const res = await delRoleById(id)
      //       // 3. 删除完毕后根据结果提醒用户
      //       this.$message.success(res.message)
      //       // 4. 重新发请求获取数据
      //       this.loadRoles()
      //     } catch (e) {
      //       this.$message.error(e.message)
      //     }
      //   })
      //   .catch(e => {})

      // axios()
      //   .then(res => {})
      //   .catch(e => {})

      // const res = await axios()

      // 优化 $confirm promise 语法
      // $confirm 的结果是 promise 对象, 所以才可以 .then  .catch
      // 当用户点击确定时, confirm 组件会进入成功的回调
      // resolved 成功的  ==>  成功的回调, 用户点确定会执行这个
      // rejected 失败的  ==>  失败的回调, 用户点取消会执行这个
      // const p =
      // this.$confirm('确定删除该角色吗?', '提示', {
      //   type: 'warning'
      // })
      //   // result 是一个字符串 confirm
      //   .then(result => {
      //     // 用户点确定时执行
      //     console.log(result)
      //   })
      //   // e 是一个字符串 cancel
      //   .catch(e => {
      //     // 用户点取消
      //     console.log(e)
      //   })
      // console.log(p)
      // p.then
      // p.catch

      // 处理异常:
      // 所有异步操作原则上来讲都需要处理异常
      // 方案1: try - catch (需要嵌套一层)
      // try {
      //   const result = await this.$confirm('确定删除该角色吗?', '提示', {
      //     type: 'warning'
      //   })
      //   console.log(result) // confirm
      // } catch (e) {
      //   console.log(e) // cancel
      // }

      // 方案2: await 结合 .catch 处理
      // await 语法糖获取的返回值就是 promise 对象 .then 第一个回调函数中的第一个参数
      // const result = await this.$confirm('确定删除该角色吗?', '提示', {
      //   type: 'warning'
      // })
      //   // .catch(e => {}) // 没有返回结果, 所以返回值是 undefined
      //   .catch(e => e) // 返回值是 e, e 是 cancel
      // // 处理异常前: 点确定 confirm, 点取消报错
      // // 需求: 知道用户点的是确定还是取消?
      // // 在 promise 的串行任务中, 每一次回调函数(包括 .then 和 .catch)中返回的结果, 会作为下一个 .then 的参数
      // // 希望点击确定打印 confirm, 点击取消打印 cancel
      // console.log(result)

      // promise 有三种状态: pending(初始状态) fullfilled(成功) rejected(失败)
      // 特点: 状态修改是不可逆的, 一旦成功就不可能再失败, 一旦失败就不可能再成功
      // 调用 resolve 的时候就是将状态改为 fullfilled
      // 调用 reject 的时候就是将状态改为 rejected
      // const p = new Promise((resolve, reject) => {
      //   // 这里的代码是同步的
      //   // 开启定时器演示
      //   setTimeout(() => {
      //     const result = 'HelloWorld'
      //     resolve(result)
      //     // reject('这是失败的结果')
      //   }, 500)
      // })

      // p
      //   .then(res => {
      //     console.log(res) // HelloWorld
      //     return res
      //   })
      //   .then(res => {
      //     console.log(res)
      //   })

      const result = await this.$confirm('确定删除该角色吗?', '提示', {
        type: 'warning'
      })
      // .then(res => {res}) // res 是 confirm
        .catch(e => e) // 返回值是 e, e 是 cancel
      // 在 promise 的串行任务中, 每一次回调函数(包括 .then 和 .catch)中返回的结果, 会作为下一个 .then 的参数
      // console.log(result)
      // 用户点击取消就直接 return
      if (result !== 'confirm') return

      // 表示用户点确定
      // 2. 用户确定后, 发请求删除
      const res = await delRoleById(id).catch(e => this.$message.error(e.message))
      // 3. 删除完毕后根据结果提醒用户
      this.$message.success(res.message)

      // 4. 处理分页的问题: 最后一页只有一个元素时
      // 所有分页的删除 Bug 都是这么处理
      if (this.roles.length === 1 && this.pageParams.page > 1) {
        this.pageParams.page--
      }

      // 5. 重新发请求获取数据
      this.loadRoles()
    },
    async hSubmit() {
      // 判断 this.isEdit 是添加还是编辑
      // if (this.isEdit) {
      // } else {
      //   this.doAdd()
      // }

      // 这里做兜底校验可以更省代码
      const valid = await this.$refs.roleForm.validate().catch(e => e)
      if (!valid) return

      this.isEdit ? this.doEdit() : this.doAdd()
    },
    hEdit(row) {
      // console.log(row)
      // 1. 打开 dialog
      this.showDialog = true

      // 2. 数据回填
      // 深拷贝
      this.roleForm = { ...row }

      // 3. 将状态改为编辑
      this.isEdit = true
    },
    hAdd() {
      // 点击添加弹出 dialog
      this.showDialog = true

      // 修改当前状态
      this.isEdit = false
    },
    hClosed() {
      // 清空表单
      this.roleForm = {
        name: '',
        description: ''
      }

      // 清空校验结果
      this.$refs.roleForm.clearValidate()
    },
    async doEdit() {
      // 1. 兜底校验 - 挪到 hSubmit 中
      // const valid = await this.$refs.roleForm.validate()
      // if (!valid) return

      // 2. 发请求
      const res = await updateRole(this.roleForm).catch(e => this.$message.error(e.message))

      // 3. 根据结果提醒用户
      this.$message.success(res.message)

      // 4. 发请求获取新的角色列表
      this.loadRoles()

      // 5. 关闭 dialog
      this.showDialog = false
    },
    async doAdd() {
      // 优化前
      // // 1. 兜底校验
      // this.$refs.roleForm.validate(async valid => {
      //   if (!valid) return
      //   // 2. 发请求
      //   const res = await addRole(this.roleForm).catch(e => this.$message.error(e.message))
      //   this.$message.success(res.message)
      //   // 3. 重新获取角色列表
      //   this.loadRoles()
      //   // 4. 关闭 dialog
      //   this.showDialog = false
      // })

      // 过渡, validate 返回的是一个 promise 对象 (如果没传回调函数)
      // // 1. 兜底校验
      // this.$refs.roleForm.validate().then(async valid => {
      //   if (!valid) return
      //   // 2. 发请求
      //   const res = await addRole(this.roleForm).catch(e => this.$message.error(e.message))
      //   this.$message.success(res.message)
      //   // 3. 重新获取角色列表
      //   this.loadRoles()
      //   // 4. 关闭 dialog
      //   this.showDialog = false
      // })

      // 优化后
      // await 后是 promise, 返回值是 promise.then 回调函数中的第一个参数
      // 通俗来讲就是成功的结果
      // 1. 兜底校验 - 挪到 hSubmit 中
      // const valid = await this.$refs.roleForm.validate()
      // if (!valid) return

      // 2. 发请求
      const res = await addRole(this.roleForm).catch(e => this.$message.error(e.message))
      this.$message.success(res.message)

      // // 跳转到最后一页
      // // 最后一页: Math.ceil(total/pagesize)
      // const maxNum = Math.ceil(this.total / this.pageParams.pagesize)

      // // 当前最后一页是否"满了": total % pagesize === 0
      // if (this.total % this.pageParams.pagesize === 0) {
      //   // 先让 total++ 再设置 page 就可以看到高亮效果了
      //   this.total++
      //   this.pageParams.page = maxNum + 1
      // } else {
      //   // pageParams.page 就是修改当前页的属性
      //   this.pageParams.page = maxNum
      // }

      // 朱悦的解决方案: 优化版
      // 智囊团终极优化版
      this.pageParams.page = Math.ceil(++this.total / this.pageParams.pagesize)

      // 3. 重新获取角色列表
      this.loadRoles()

      // 4. 关闭 dialog
      this.showDialog = false
    },
    hAssign(id) {
      this.roleId = id
      // 显示 dialog
      this.showDialogAssign = true
    }
  }
}
</script>
